package com.jvmmonitor.agent;

import java.lang.reflect.Constructor;
import java.util.Random;

import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.This;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jvmmonitor.service.ObjectSizeMonitor;
import com.jvmmonitor.util.ConfigLoader;
import com.jvmmonitor.util.ObjectSizeCalculator;

/**
 * 对象大小拦截器，用于监控对象创建
 */
public class ObjectSizeInterceptor {
    private static final Logger logger = LoggerFactory.getLogger(ObjectSizeInterceptor.class);
    
    // 随机数生成器，用于采样
    private static final Random random = new Random();
    
    /**
     * 构造方法拦截器
     * @param obj 创建的对象实例
     * @param constructor 构造方法
     * @param args 构造方法参数
     */
    @RuntimeType
    public static void intercept(@This Object obj, @Origin Constructor<?> constructor, @AllArguments Object[] args) {
        try {
            // 计算对象大小
            long objectSize = ObjectSizeCalculator.calculateObjectSize(obj);
            
            // 获取ObjectSizeMonitor实例
            ObjectSizeMonitor objectSizeMonitor = getObjectSizeMonitor();
            
            // 更新对象大小统计
            objectSizeMonitor.updateObjectSizeStats(obj.getClass().getName(), objectSize);
            
            // 记录对象创建日志（如果开启）
            logObjectCreation(obj, constructor, objectSize);
        } catch (Exception e) {
            logger.warn("Failed to intercept object creation: {}", e.getMessage());
        }
    }
    
    /**
     * 获取ObjectSizeMonitor实例
     */
    private static ObjectSizeMonitor getObjectSizeMonitor() {
        JvmMonitorAgent agent = JvmMonitorAgent.getInstance();
        if (agent != null) {
            // 通过反射获取agent中的objectSizeMonitor字段
            try {
                java.lang.reflect.Field field = agent.getClass().getDeclaredField("objectSizeMonitor");
                field.setAccessible(true);
                return (ObjectSizeMonitor) field.get(agent);
            } catch (Exception e) {
                logger.warn("Failed to get ObjectSizeMonitor from agent: {}", e.getMessage());
            }
        }
        // 备选方案：返回一个新实例（应该不会执行到这里）
        logger.warn("Using new ObjectSizeMonitor instance");
        return new ObjectSizeMonitor();
    }
    
    /**
     * 记录对象创建日志
     * @param obj 创建的对象
     * @param constructor 构造方法
     * @param objectSize 对象大小
     */
    private static void logObjectCreation(Object obj, Constructor<?> constructor, long objectSize) {
        // 检查对象创建日志是否开启
        if (!ConfigLoader.isObjectCreateLogEnabled()) {
            return;
        }
        
        // 检查是否需要采样
        int samplingRate = ConfigLoader.getObjectCreateLogSamplingRate();
        if (samplingRate < 100 && random.nextInt(100) >= samplingRate) {
            return;
        }
        
        // 获取类名和方法名
        String className = constructor.getDeclaringClass().getName();
        String constructorName = className + "(";
        
        // 构建构造方法参数列表
        Class<?>[] parameterTypes = constructor.getParameterTypes();
        for (int i = 0; i < parameterTypes.length; i++) {
            if (i > 0) {
                constructorName += ", ";
            }
            constructorName += parameterTypes[i].getSimpleName();
        }
        constructorName += ")";
        
        // 获取调用堆栈信息
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        String callerInfo = getCallerInfo(stackTrace);
        
        // 记录对象创建日志
        logger.debug("Object Created: {}", obj);
        logger.debug("  Size: {} bytes", objectSize);
        logger.debug("  Constructor: {}", constructorName);
        logger.debug("  Thread: {}", Thread.currentThread().getName());
        logger.debug("  Caller: {}", callerInfo);
    }
    
    /**
     * 从堆栈跟踪中获取调用者信息
     * @param stackTrace 堆栈跟踪
     * @return 调用者信息
     */
    private static String getCallerInfo(StackTraceElement[] stackTrace) {
        // 跳过前几个堆栈元素（当前方法、拦截器方法等）
        for (int i = 3; i < stackTrace.length; i++) {
            StackTraceElement element = stackTrace[i];
            String className = element.getClassName();
            
            // 跳过ByteBuddy和监控相关类
            if (!className.startsWith("net.bytebuddy.") && 
                !className.startsWith("com.jvmmonitor.") &&
                !className.startsWith("java.lang.reflect.") &&
                !className.startsWith("sun.reflect.") &&
                !className.equals(Thread.class.getName())) {
                
                return String.format("%s.%s(%s:%d)", 
                    className, 
                    element.getMethodName(), 
                    element.getFileName(), 
                    element.getLineNumber());
            }
        }
        
        return "Unknown caller";
    }
}